package com.iflyings.android.util

import android.annotation.SuppressLint
import android.content.Context
import android.net.LinkAddress
import android.os.Build
import java.net.Inet4Address
import java.net.InetAddress
import java.util.regex.Pattern

class EthernetManager(context: Context) {

    companion object {
        @SuppressLint("PrivateApi")
        private val EthManagerCls = Class.forName("android.net.EthernetManager")
        @SuppressLint("PrivateApi")
        private val IpConfigurationCls = Class.forName("android.net.IpConfiguration")
        @SuppressLint("PrivateApi")
        private val StaticIpConfigurationCls = Class.forName("android.net.StaticIpConfiguration")
    }

    @SuppressLint("WrongConstant")
    private val mEthManager = context.getSystemService("ethernet")

    private fun getIpConfigurationEnum(): Map<String, Any> {
        val enumMap: MutableMap<String, Any> = HashMap()
        val enumClass = IpConfigurationCls.declaredClasses
        for (enumC in enumClass) {
            val enumConstants = enumC.enumConstants ?: continue
            for (enu in enumConstants) {
                enumMap[enumC.simpleName + "." + enu.toString()] = enu
            }
        }
        return enumMap
    }

    private fun getPrefixLength(maskStr: String): Int {
        var sb: StringBuffer
        var str: String
        var inetmask = 0
        var count = 0
        /*
         * check the subMask format
         */
        val pattern = Pattern.compile("(^((\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])$)|^(\\d|[1-2]\\d|3[0-2])$")
        if (!pattern.matcher(maskStr).matches()) {
            return 0
        }

        val ipSegment = maskStr.split("\\.".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
        for (n in ipSegment.indices) {
            sb = StringBuffer(Integer.toBinaryString(ipSegment[n].toInt()))
            str = sb.reverse().toString()
            count = 0
            var i = 0
            while (i < str.length) {
                i = str.indexOf("1", i)
                if (i == -1) break
                count++
                i++
            }
            inetmask += count
        }
        return inetmask
    }


    private fun newLinkAddress(address: String, mask: String): Any {
        val linkAddressCls = Class.forName("android.net.LinkAddress")
        val linkAddressConstructor = linkAddressCls.getDeclaredConstructor(
            InetAddress::class.java, Int::class.javaPrimitiveType
        )
        return linkAddressConstructor.newInstance(
            InetAddress.getByName(address),
            getPrefixLength(mask)
        )
    }

    /**
     * 获取StaticIpConfiguration实例
     */
    @SuppressLint("PrivateApi")
    private fun newStaticIpConfiguration(address: String, gate: String, mask: String, dns1: String, dns2: String): Any {
        //实例化StaticIpConfiguration
        val staticIpConfiguration = StaticIpConfigurationCls.getDeclaredConstructor().newInstance()
        val ipAddress = StaticIpConfigurationCls.getField("ipAddress")
        val gateway = StaticIpConfigurationCls.getField("gateway")
        val domains = StaticIpConfigurationCls.getField("domains")
        val dnsServers = StaticIpConfigurationCls.getField("dnsServers")
        //设置ipAddress
        ipAddress[staticIpConfiguration] = newLinkAddress(address, mask)
        //设置网关
        gateway[staticIpConfiguration] = InetAddress.getByName(gate)
        //设置掩码
        //domains[staticIpConfiguration] = mask
        //设置dns
        val dnsList = dnsServers[staticIpConfiguration] as ArrayList<InetAddress>
        dnsList.add(InetAddress.getByName(dns1))
        dnsList.add(InetAddress.getByName(dns2))
        return staticIpConfiguration
    }

    private fun newIpConfiguration(staticIpConfiguration: Any): Any {
        val ipConfiguration = IpConfigurationCls.getDeclaredConstructor().newInstance()
        //设置StaticIpConfiguration
        val staticIpConfigurationField = IpConfigurationCls.getField("staticIpConfiguration")
        staticIpConfigurationField[ipConfiguration] = staticIpConfiguration
        //获取ipAssignment、proxySettings的枚举值
        val ipConfigurationEnum = getIpConfigurationEnum()
        //设置ipAssignment
        val ipAssignment = IpConfigurationCls.getField("ipAssignment")
        ipAssignment[ipConfiguration] = ipConfigurationEnum["IpAssignment.STATIC"]
        //设置proxySettings
        val proxySettings = IpConfigurationCls.getField("proxySettings")
        proxySettings[ipConfiguration] = ipConfigurationEnum["ProxySettings.NONE"]
        return ipConfiguration
    }

    @SuppressLint("PrivateApi")
    private fun getConfiguration(): Any? {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val getConfigurationMethod = EthManagerCls.getDeclaredMethod("getConfiguration", String::class.java)
            return getConfigurationMethod.invoke(mEthManager, "eth0")
        } else {
            val getConfigurationMethod = EthManagerCls.getDeclaredMethod("getConfiguration")
            return getConfigurationMethod.invoke(mEthManager)
        }
    }

    @SuppressLint("PrivateApi")
    private fun setConfiguration(config: Any) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            val ipConfiguration = IpConfigurationCls.getDeclaredConstructor().newInstance()
            val setConfigurationMethod = EthManagerCls.getDeclaredMethod("setConfiguration", String::class.java,
                ipConfiguration.javaClass)
            setConfigurationMethod.invoke(mEthManager, "eth0", config)
        } else {
            val ipConfiguration = IpConfigurationCls.getDeclaredConstructor().newInstance()
            val setConfigurationMethod = EthManagerCls.getDeclaredMethod("setConfiguration", ipConfiguration.javaClass)
            setConfigurationMethod.invoke(mEthManager, config)
        }

    }

    @SuppressLint("PrivateApi")
    fun isDhcpIp(): Boolean {
        val ipConfiguration = getConfiguration()
        //获取IpConfiguration的getIpAssignment()
        val getIpAssignmentMethod = IpConfigurationCls.getDeclaredMethod("getIpAssignment")
        //获取EthernetManager的getConfiguration()
        val ipAssignment =
            getIpAssignmentMethod.invoke(ipConfiguration) //ipConfiguration.getConfiguration().getIpAssignment();
        //获取ipAssignment、proxySettings的枚举值
        val ipConfigurationEnum = getIpConfigurationEnum()
        return ipAssignment == ipConfigurationEnum["IpAssignment.DHCP"] ||
                ipAssignment == ipConfigurationEnum["IpAssignment.UNASSIGNED"]
    }

    @SuppressLint("PrivateApi")
    fun setDhcpIp(): Boolean {
        return try {
            if (isDhcpIp()) {
                return true
            }
            val ipConfiguration = IpConfigurationCls.getDeclaredConstructor().newInstance()
            //获取ipAssignment、proxySettings的枚举值
            val ipConfigurationEnum = getIpConfigurationEnum()
            //设置ipAssignment
            val ipAssignment = IpConfigurationCls.getField("ipAssignment")
            ipAssignment[ipConfiguration] = ipConfigurationEnum["IpAssignment.DHCP"]
            //设置proxySettings
            val proxySettings = IpConfigurationCls.getField("proxySettings")
            proxySettings[ipConfiguration] = ipConfigurationEnum["ProxySettings.NONE"]
            //获取EthernetManager的setConfiguration()
            setConfiguration(ipConfiguration)
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    @SuppressLint("PrivateApi")
    fun setStaticIp(address: String, mask: String, gate: String, dns1: String, dns2: String): Boolean {
        return try {
            //创建StaticIpConfiguration
            val staticIpConfiguration = newStaticIpConfiguration(address, gate, mask, dns1, dns2)
            //创建IpConfiguration
            val ipConfiguration = newIpConfiguration(staticIpConfiguration)
            //设置静态IP
            setConfiguration(ipConfiguration)
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    @SuppressLint("PrivateApi")
    fun getIpConfiguration(): Map<String, String> {
        val map = mutableMapOf<String, String>()
        val ipConfiguration = getConfiguration()
        val ipAssignment = IpConfigurationCls.getDeclaredMethod("getIpAssignment")
            .invoke(ipConfiguration)
        val ipConfigurationEnum = getIpConfigurationEnum()
        if (ipAssignment == ipConfigurationEnum["IpAssignment.DHCP"]) {
            map["mode"] = "DHCP"
        } else {
            map["mode"] = "STATIC"
            val staticIpConfiguration = IpConfigurationCls.getField("staticIpConfiguration").get(ipConfiguration)
            val ipAddress = StaticIpConfigurationCls.getField("ipAddress").get(staticIpConfiguration) as LinkAddress
            map["ipAddress"] = numericToTextFormat(ipAddress.address.address)
            map["mask"] = getSubnetMask(ipAddress.prefixLength)
            val gateway = StaticIpConfigurationCls.getField("gateway").get(staticIpConfiguration) as Inet4Address
            map["gateway"] = gateway.hostAddress ?: ""
            val domains = StaticIpConfigurationCls.getField("domains").get(staticIpConfiguration)
            map["domains"] = domains?.toString() ?: ""
            val dnsServers = StaticIpConfigurationCls.getField("dnsServers").get(staticIpConfiguration) as ArrayList<Inet4Address>
            dnsServers.forEachIndexed { index, dns ->
                map["dns${index+1}"] = dns.hostAddress ?: ""
            }
        }
        return map
    }

    private fun numericToTextFormat(src: ByteArray): String {
        return (src[0].toInt() and 0xff).toString() + "." + (src[1].toInt() and 0xff) + "." + (src[2].toInt() and 0xff) + "." + (src[3].toInt() and 0xff)
    }
    private fun getSubnetMask(prefixLength: Int):String{
        val subnetMask = -0x1 shl (32 - prefixLength)
        return ((subnetMask shr 24) and 0xff).toString() + "." +
                ((subnetMask shr 16) and 0xff) + "." +
                ((subnetMask shr 8) and 0xff) + "." +
                (subnetMask and 0xff)
    }
}